from flask import Flask, Response, request, jsonify, g, render_template
import redis
from functools import wraps
from os import environ
from redis.exceptions import ConnectionError

app = Flask(__name__)

try:
    cfg = environ['FLASK_MYAPP_CONFIG']
    print('Setting config:%s' %cfg)
    app.config.from_object(cfg)
except Exception,  e:
    print e
    print('Setting defaut DevelopmentConfig.')
    app.config.from_object('config.DevelopmentConfig')


logger = app.logger
logger.setLevel(app.config['LOG_LEVEL'])

KEY_USERS = 'users'

ERROR_CONNECTION_MSG = {'error':'Connection Error'}

def check_auth(username, password):
    
    """ Check if a username password combination is valid. """
    return username == app.config['USER'] and password == app.config['PASSWORD']


def authenticate():
    """Sends a 401 response that enables basic auth"""
    return Response(
    'Could not verify your access level for that URL.\n'
    'You have to login with proper credentials', 401,
    {'WWW-Authenticate': 'Basic realm="Login Required"'})
    

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated


@app.before_request
def before_request():
    if app.config['REDIS_PASSWORD']:
        g.r_server = redis.Redis(app.config['REDIS_HOST'], app.config['REDIS_PORT'], 
                                 password=app.config['REDIS_PASSWORD'])
    else:
        g.r_server = redis.Redis(app.config['REDIS_HOST'], app.config['REDIS_PORT'])


@app.teardown_request
def teardown_request(exception): 
    if g.r_server is not None:
        g.r_server = None


@app.route('/')
def index():
    # TODO show an html usage page.
    return 'index page'


def __user_key(username):
    # key user format
    return '%s:%s' %(KEY_USERS, username)

        
@app.route('/get/<username>' , methods=['GET'])
@requires_auth
def get_credit(username):

    # it gets the number of credits from redis
    credit = g.r_server.get(__user_key(username))

    if credit:
        
        return jsonify(username=username , credit=credit)
    
    return jsonify(error='no user found')

  
@app.route('/set/<username>/<int:credit>', methods=['POST', 'PUT'])
@requires_auth
def set_credit(username, credit):

    # request.args.get('key', '')
    
    # it gets the number of credits from redis
    if credit == None:
        credit = 100
        
    res = g.r_server.set(__user_key(username), int(credit))
    logger.info('set %d credit for user %s' %(credit, username))
    
    return jsonify(result=res, 
                       username=username,
                       credit=credit)
    
@app.route('/consume/<username>', methods=['POST'])
@app.route('/consume/<username>/<int:credit>', methods=['POST'])
@requires_auth
def consume(username, credit=1):

    try:
        res_credit =  g.r_server.get(__user_key(username))

        if res_credit:

            if (int(res_credit) - int(credit)) > 0:       
                res = g.r_server.decr(__user_key(username), credit)
                logger.info('consume %d credit for user %s' %(credit, username))
        
                return jsonify(username=username, credit=res)
            else:
                # no sufficient credit
                return jsonify(username=username,
                               error="Not enought credit",
                               res_credit=res_credit)

        return jsonify(error='no user found')
        
    except ConnectionError, e:
        logger.error('Redis Connection error')
        logger.error(e)
        return jsonify(ERROR_CONNECTION_MSG)



@app.route('/users/', methods=['GET', 'POST'])
@requires_auth
def get_users():
    
    return __get_users__()


def __get_users__(user='*'):
    
    try:
        users = g.r_server.keys('%s:%s' %(KEY_USERS, user))

        credit_lst = {}

        for u in users:
            credit_lst[u] = g.r_server.get(u)

        return jsonify(users=credit_lst)
    
    except ConnectionError, e:
        logger.error('Redis Connection error')
        logger.error(e)
        return jsonify(ERROR_CONNECTION_MSG)


@app.route('/users.html', methods=['GET', 'POST'])
def search_users():
     
    if request.method == 'GET':
        return render_template('users.html')
    elif request.method == 'POST':
        user = request.form['q']
        logger.debug('Search for user %s' %user)
        
        return __get_users__(user)


if __name__ == '__main__':
    app.run()
